package com.lagou.zookeeper.zktest;

import com.alibaba.druid.pool.DruidDataSource;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.ToString;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

@SpringBootApplication
public class ZktestApplication {
    //JDBC配置
    @Data
    @ToString
    static
    class JDBCConfig{
        private String url;
        private String driver = "com.mysql.jdbc.Driver";
        private String username;
        private String password;
    }
    static class ZkStrSerializer implements ZkSerializer {

        @Override
        public byte[] serialize(Object o) throws ZkMarshallingError {
            return String.valueOf(o).getBytes();
        }

        @Override
        public Object deserialize(byte[] bytes) throws ZkMarshallingError {
            return new String(bytes);
        }
    }
    final static String CONFIG_PATH="/JDBCConfig";
    private static ZkClient zkClient = null;
    private static DruidDataSource druidDataSource = null;
    final static String DEFAULT_TEST_SQL="select 1 from dual";
    private static ObjectMapper mapper = new ObjectMapper();

    //链接到zk服务
    private static void initZk(){
        zkClient = new ZkClient("127.0.0.1:2181");
        zkClient.setZkSerializer(new ZkStrSerializer());
        zkClient.subscribeDataChanges(CONFIG_PATH, new IZkDataListener() {
            public void handleDataChange(String path, Object data) {
                System.out.println(path + " data is changed, new data " + data);
                druidDataSource.close();
                configDataSource();
            }
            public void handleDataDeleted(String path) {
                System.out.println(path + " is deleted!!");
                druidDataSource.close();
            }
        });
    }
    //从ZK获取jdbc配置
    private static JDBCConfig getJdbcConfig(){
        Object o = zkClient.readData(CONFIG_PATH);
        try {
            JDBCConfig myConfig = mapper.readValue(o.toString(), JDBCConfig.class);
            System.out.println(myConfig.toString());
            return myConfig;
        } catch (JsonProcessingException e) {
            return new JDBCConfig();
        }
    }
    //初始化连接池
    private static void initDataSource(JDBCConfig config){
        druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(config.url);
        druidDataSource.setDriverClassName(config.driver);
        druidDataSource.setUsername(config.username);
        druidDataSource.setPassword(config.password);
        druidDataSource.setMaxActive(20);
        druidDataSource.setInitialSize(1);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setMinIdle(1);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(300000);
        druidDataSource.setValidationQuery(DEFAULT_TEST_SQL);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(true);
        druidDataSource.setTestOnReturn(true);
        druidDataSource.setPoolPreparedStatements(true);
        druidDataSource.setMaxOpenPreparedStatements(20);
    }
    //配置数据库连接池
    private static void configDataSource(){
        JDBCConfig config = getJdbcConfig();
        initDataSource(config);
        //获取链接发送测试sql
        try{
            Connection connection = druidDataSource.getConnection();
            PreparedStatement pst = connection.prepareStatement( "SELECT id, username FROM user;" );
            ResultSet rs = pst.executeQuery();
            while (rs.next()) {
                System.out.println("id : " + rs.getString(1) + " , username : " + rs.getString(2));
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(ZktestApplication.class, args);
        initZk();
        configDataSource();
    }

}
